﻿using System;
using System.Linq;
using System.Web;
using System.IO;

using HQPad.Models;
using Sib = Siberix.Report;

namespace HQPad.Helpers
{
    public class BattleboardCallback : Sib.ICallback
    {
        private BattleboardModel model;

        public BattleboardCallback(BattleboardModel model)
        {
            this.model = model;
        }

        #region OnMergeCode
        /// <summary>
        /// Handle the Siberix report creation merge code callback.
        /// </summary>
        /// <param name="mergeCodeName">The merge code name.</param>
        /// <returns></returns>
        public string OnMergeCode(string mergeCodeName)
        {
            string data = string.Empty;

            if (mergeCodeName == "CharacterName")
            {
                data = model.CharacterName;
            }
            else if (mergeCodeName == "CharacterRace")
            {
                data = model.CharacterRace;
            }
            else if (mergeCodeName == "CharacterClass")
            {
                data = model.CharacterClass;
            }
            else if (mergeCodeName == "CharacterRank")
            {
                data = model.CharacterRank;
            }
            else if (mergeCodeName.EndsWith("AC"))
            {
                data = GetACRecord(mergeCodeName);
            }
            else if (mergeCodeName == "GenDate")
            {
                data = DateTime.Now.ToString("dd MMM yyyy HH:mm");
            }
            else if (mergeCodeName.StartsWith("SpellSlots"))
            {
                data = GetSlotRecord(mergeCodeName);
            }
            else if (mergeCodeName.StartsWith("TotalPower"))
            {
                data = model.TotalPower.ToString();
            }
            else if (mergeCodeName.StartsWith("Life_Total"))
            {
                data = model.Life.TotalLife.ToString();
            }
            else if (mergeCodeName.StartsWith("Life_Body"))
            {
                data = (model.Life.LocationalLife * 2).ToString();
            }
            else if (mergeCodeName.StartsWith("Life_Limb"))
            {
                data = model.Life.LocationalLife.ToString();
            }
            
            return data;
        }
        #endregion

        #region GetSlotRecord
        /// <summary>
        /// Get the relevant spell slot data for the magic section.
        /// </summary>
        /// <param name="mergeCode"></param>
        /// <returns></returns>
        protected string GetSlotRecord(string mergeCode)
        {
            string data = string.Empty;

            string[] parts = mergeCode.Split('_');

            int level = int.Parse(parts[2]);

            SpellLevelSlot slot = model.Spells.Where(a => a.Level == level).FirstOrDefault();

            if (slot != null)
            {
                switch (parts[1].ToLower())
                {
                    case "level":
                        data = level.ToString();
                        break;
                    case "total":
                        data = slot.Spells.ToString();
                        break;
                    case "out":
                        data = string.Empty;
                        break;
                    default:
                        break;
                }
            }

            return data;
        }
        #endregion

        #region GetACRecord
        /// <summary>
        /// Extract the correct merge code value from the AC list.
        /// </summary>
        /// <param name="mergeCode"></param>
        /// <returns></returns>
        protected string GetACRecord(string mergeCode)
        {
            string data = "0";

            ACRecord record = null;

            if (mergeCode.Contains("Physical"))
            {
                record = model.ArmourClasses.Find(a => a.Name == "Physical");
            }
            else if (mergeCode.Contains("Power"))
            {
                record = model.ArmourClasses.Find(a => a.Name == "Power");
            }
            else if (mergeCode.Contains("Magical"))
            {
                record = model.ArmourClasses.Find(a => a.Name == "Magical");
            }
            else if (mergeCode.Contains("Dex"))
            {
                record = model.ArmourClasses.Find(a => a.Name == "Dex");
            }
            else if (mergeCode.Contains("Evil"))
            {
                record = model.ArmourClasses.Find(a => a.Name == "Evil");
            }
            else if (mergeCode.Contains("Undead"))
            {
                record = model.ArmourClasses.Find(a => a.Name == "Undead");
            }
            else if (mergeCode.Contains("Psi"))
            {
                record = model.ArmourClasses.Find(a => a.Name == "Psi");
            }

            if (record == null)
                return data;

            if (mergeCode.Contains("Pure"))
                data = record.Pure.ToString();
            else if (mergeCode.Contains("Total"))
                data = record.Total.ToString();

            return data;
        }
        #endregion

        public void OnInjector(string name, Siberix.Report.Text.IText text, Siberix.Report.Text.Style style, Siberix.Report.Text.Hyperlink hyperlink)
        {
        }

        #region OnInjector (Group)
        /// <summary>
        /// Group element injector
        /// </summary>
        /// <param name="injectorName"></param>
        /// <param name="group"></param>
        public void OnInjector(string injectorName, Siberix.Report.IGroup group)
        {
            // Shared objects.
            Siberix.Graphics.Pen linePen = new Siberix.Graphics.Pen(new Siberix.Graphics.Color(255, 29, 29, 29), 1, Siberix.Graphics.DashStyle.Solid);
            Sib.Text.Style small = new Sib.Text.Style(new Siberix.Graphics.Fonts.Arial(9), new Siberix.Graphics.SolidColorBrush(new Siberix.Graphics.Color(255, 29, 29, 29)));
            Sib.Text.Style smallBold = new Sib.Text.Style(new Siberix.Graphics.Fonts.ArialBold(9), new Siberix.Graphics.SolidColorBrush(new Siberix.Graphics.Color(255, 29, 29, 29)));
            Sib.Text.Style normalBold = new Sib.Text.Style(new Siberix.Graphics.Fonts.ArialBold(11), new Siberix.Graphics.SolidColorBrush(new Siberix.Graphics.Color(255, 29, 29, 29)));

            if (injectorName == "EquippedArmour")
            {
                if (model.Armours != null && model.Armours.Count > 0)
                {
                    group.Spacings.Top = 5;
                    Sib.Text.IText textTitle = group.AddText();
                    textTitle.Style = smallBold;
                    textTitle.AddContent("Armour:");

                    foreach (string armour in model.Armours)
                    {
                        Sib.Text.IText text = group.AddText();
                        text.Style = small;
                        text.AddContent(armour);
                    }
                }
            }
            else if (injectorName == "Mnenomic_Tick")
            {
                if (!model.CanMnenomic)
                {
                    Siberix.Graphics.Image tickImage = new Siberix.Graphics.Image(LoadImage("mnenomic_tick.png"));
                    Sib.IImage image = group.AddImage(tickImage);
                    image.Width = new Sib.DirectWidth(15);
                    image.Height = new Sib.DirectHeight(15);
                }
            }
            else if (injectorName == "Mnenomic_Boxes")
            {
                if (model.CanMnenomic)
                {

                    Sib.Grid.IGrid grid = group.AddGrid();

                    grid.Borders.All = new Sib.Border(linePen);

                    Sib.Grid.IColumn col1 = grid.AddColumn();
                    col1.Width = new Sib.RelativeWidth(25);

                    Sib.Grid.IColumn col2 = grid.AddColumn();
                    col2.Width = new Sib.RelativeWidth(25);
                    
                    Sib.Grid.IColumn col3 = grid.AddColumn();
                    col3.Width = new Sib.RelativeWidth(25);

                    Sib.Grid.IColumn col4 = grid.AddColumn();
                    col4.Width = new Sib.RelativeWidth(25);

                    Sib.Grid.IColumn col5 = grid.AddColumn();
                    col5.Width = new Sib.RelativeWidth(25);

                    Sib.Grid.IRow row = grid.AddRow();
                    row.Height = new Sib.DirectHeight(10);

                    Sib.Grid.ICell cell1 = row.AddCell();
                    cell1.Borders.Right = new Sib.Border(linePen);

                    Sib.Grid.ICell cell2 = row.AddCell();
                    cell2.Borders.Right = new Sib.Border(linePen);
                    
                    Sib.Grid.ICell cell3 = row.AddCell();
                    cell3.Borders.Right = new Sib.Border(linePen);

                    Sib.Grid.ICell cell4 = row.AddCell();
                    cell4.Borders.Right = new Sib.Border(linePen);

                    Sib.Grid.ICell cell5 = row.AddCell();
                }
            }
            else if (injectorName == "Power_In_Talisman")
            {
                if (!model.HasTalisman)
                    return;

                // create single box.
                Sib.IGroup box = group.AddGroup();
                box.Borders.All = new Sib.Border(linePen);
                box.Paddings.Top = 1;
                box.Paddings.Bottom = 1;
                box.Width = new Sib.DirectWidth(20);
                box.Height = new Sib.DirectHeight(18);
                box.Alignment.Horizontal = Sib.HorizontalAlignment.Center;
                box.Alignment.Vertical = Sib.VerticalAlignment.Middle;

                Sib.Text.IText text = box.AddText();
                text.Style = normalBold;
                text.AddContent(model.TalismanPower.ToString());
            }
            else if (injectorName == "Power_In_Self")
            {
                if (!model.HasTalisman)
                    return;

                // create single box.
                Sib.IGroup box = group.AddGroup();
                box.Borders.All = new Sib.Border(linePen);
                box.Paddings.Top = 1;
                box.Paddings.Bottom = 1;
                box.Width = new Sib.DirectWidth(25);
                box.Height = new Sib.DirectHeight(18);
                box.Alignment.Horizontal = Sib.HorizontalAlignment.Center;
                box.Alignment.Vertical = Sib.VerticalAlignment.Middle;

                Sib.Text.IText text = box.AddText();
                text.Style = normalBold;
                text.AddContent((model.TotalPower - model.TalismanPower).ToString());
            }
            else if (injectorName == "Power_In_Self_Label")
            {
                if (!model.HasTalisman)
                    return;

                Sib.Text.IText text = group.AddText();
                group.Alignment.Horizontal = Sib.HorizontalAlignment.Right;
                text.Style = normalBold;
                text.AddContent("Self: ");
            }
            else if (injectorName == "Items_And_Abilites")
            {
                // Create grid of rows.
                Sib.Grid.IGrid grid = group.AddGrid();
                Sib.Grid.IColumn col = grid.AddColumn();
                

                if (model.Items == null || model.Items.Count == 0)
                {
                    // Add six blank rows.
                    for (int i = 0; i < 6; i++)
                        AddItemGridRow(grid, string.Empty, string.Empty, 0);

                    return;
                }

                int count = 0;

                foreach (ItemBase item in model.Items)
                {
                    count++;
                    string description = item.Name;
                    string recharge = string.Empty;
                    int charges = 0;

                    switch (item.Type)
                    {
                        case ItemType.Ability:
                        {
                            Ability ability = (Ability)item;

                            if (ability.Use == ItemUseType.OnceEver)
                            {
                                recharge = "Once ever";
                                charges = 1;
                            }
                            else if (ability.Use == ItemUseType.Charged)
                            {
                                recharge = "Charged";
                                int.TryParse(ability.Charges, out charges);
                            }
                            else if (ability.Use == ItemUseType.Recharges)
                            {
                                recharge = ability.Frequency;
                                int.TryParse(ability.Charges, out charges);
                            }
                            else if (ability.Use == ItemUseType.Unlimited)
                            {
                                recharge = "Unlimited charges";
                            }
                            break;
                        }
                        case ItemType.Item:
                        {
                            Item itm = (Item)item;
                            if (itm.Use == ItemUseType.OnceEver)
                            {
                                recharge = "Once ever";
                                charges = 1;
                            }
                            else if (itm.Use == ItemUseType.Charged)
                            {
                                recharge = "Charged";
                                charges= itm.Charges;
                            }
                            else if (itm.Use == ItemUseType.Recharges)
                            {
                                recharge = itm.Frequency;
                                charges = itm.Charges;
                            }
                            else if (itm.Use == ItemUseType.Unlimited)
                            {
                                recharge = "Unlimited charges";
                            }
                            break;
                        }
                    }

                    AddItemGridRow(grid, description, recharge, charges);
                }

                // Add 3 extra blank rows.
                for (int i = 0; i < 3; i++)
                    AddItemGridRow(grid, string.Empty, string.Empty, 0);

            }
        }
        #endregion

        #region AddItemGridRow
        /// <summary>
        /// Add an item or ability row.
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="description"></param>
        /// <param name="recharge"></param>
        /// <param name="charges"></param>
        protected void AddItemGridRow(Sib.Grid.IGrid grid, string description, string recharge, int charges)
        {
            Siberix.Graphics.Pen linePen = new Siberix.Graphics.Pen(new Siberix.Graphics.Color(255, 29, 29, 29), 1, Siberix.Graphics.DashStyle.Solid);
            Sib.Text.Style small = new Sib.Text.Style(new Siberix.Graphics.Fonts.Arial(9), new Siberix.Graphics.SolidColorBrush(new Siberix.Graphics.Color(255, 29, 29, 29)));
            Sib.Text.Style smallItalic = new Sib.Text.Style(new Siberix.Graphics.Fonts.ArialItalic(9), new Siberix.Graphics.SolidColorBrush(new Siberix.Graphics.Color(255, 29, 29, 29)));

            Sib.Grid.IRow row = grid.AddRow();
            Sib.Grid.ICell cell = row.AddCell();

            Sib.Grid.IGrid subGrid = cell.AddGrid();
            Sib.Grid.IColumn col = subGrid.AddColumn();

            if (charges > 0)
            {
                Sib.Grid.IColumn col2 = subGrid.AddColumn();
            }

            Sib.Grid.IRow subRow = subGrid.AddRow();
            subRow.Height = new Sib.DirectHeight(20);

            Sib.Grid.ICell cell1 = subRow.AddCell();
            cell1.Borders.Bottom = new Sib.Border(linePen);
            cell1.Borders.Left = new Sib.Border(linePen);
            
            if (charges <= 0)
                cell1.Borders.Right = new Sib.Border(linePen);

            cell1.Paddings.Top = 4;
            cell1.Paddings.Left = 5;
            cell1.Paddings.Bottom = 3;

            Sib.Text.IText text = cell1.AddText();
            text.Style = small;
            text.AddContent(description);

            if (!string.IsNullOrEmpty(recharge))
            {
                text.AddContent(string.Format(" ({0})", recharge), smallItalic);
            }

            if (charges > 0)
            {
                Sib.Grid.ICell chargesCell = subRow.AddCell();
                chargesCell.Borders.Bottom = new Sib.Border(linePen);
                chargesCell.Borders.Right = new Sib.Border(linePen);
                chargesCell.Paddings.Top = 3;
                chargesCell.Paddings.Right = 5;
                chargesCell.Paddings.Bottom = 3;
                chargesCell.Alignment.Horizontal = Sib.HorizontalAlignment.Right;

                Sib.Grid.IGrid chgGrid = chargesCell.AddGrid();
                chgGrid.Width = new Sib.DirectWidth(15 * charges);

                for (int i = 0; i < charges; i++)
                {
                    Sib.Grid.IColumn chgCol = chgGrid.AddColumn();
                    chgCol.Width = new Sib.DirectWidth(15);
                }

                Sib.Grid.IRow chgRow = chgGrid.AddRow();
                chgRow.Height = new Sib.DirectHeight(15);

                for (int i = 0; i < charges; i++)
                {
                    Sib.Grid.ICell chgCell = chgRow.AddCell();
                    chgCell.Borders.All = new Sib.Border(linePen);
                }
            }
        }
        #endregion

        public void OnInjector(string name, Siberix.Report.ISite site)
        {
        }

        public void OnInjector(string name, Siberix.Report.ICanvas canvas)
        {
        }

        public Siberix.Report.Text.Style GetStyle(string name)
        {
            return null;
        }

        public Stream LoadFont(string path)
        {
            return null;
        }

        public Stream LoadImage(string path)
        {
            if (path == "focus_tick.png")
            {
                if (model.HasFocus)
                    path = "tick.png";
                else
                    path = "cross.png";
            }
            else if (path == "mnenomic_tick.png")
            {
                if (model.CanMnenomic)
                    path = "tick.png";
                else
                    path = "cross.png";
            }
            else if (path == "talisman_tick.png")
            {
                if (model.HasTalisman)
                    path = "tick.png";
                else
                    path = "cross.png";
            }

            path = string.Format("/content/images/battleboard/{0}", path);

            string absolutePath = HttpContext.Current.Server.MapPath(path);

            if (!File.Exists(absolutePath))
                return null;

            MemoryStream dataStore = new MemoryStream();
            FileStream reader = File.OpenRead(absolutePath);

            int read = 0;

            do
            {
                byte[] buffer = new byte[1024];
                read = reader.Read(buffer, 0, 1024);

                if (read > 0)
                    dataStore.Write(buffer, 0, read);
            }
            while (read > 0);

            return dataStore;
        }

        public Siberix.Report.IDrawing OnDrawing(string name)
        {
            return null;
        }

        public string ResolvePath(string path)
        {
            return path;
        }
    }
}